
package com.trydofor.id.body.shell;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import com.trydofor.aloe.exception.Exceptions;
import com.trydofor.id.byta.Bytable;
import com.trydofor.id.byta.ByteMeta;
import com.trydofor.id.byta.Bytes;

/**
 * system command
 * 
 * @author : Shi Rongjiu (www.trydofor.com)
 */
public class ShellQueryBody implements Bytable<ShellQueryBody> {
    
    private final String              command;
    private final Map<String, String> argdata;
    
    /**
     * constructor
     * 
     * @param name the command name
     * @throws NullPointerException if name is null
     */
    public ShellQueryBody(String name) {
        Exceptions.checkNullPointer(name);
        command = name;
        argdata = new HashMap<String, String>();
    }
    
    /**
     * {@inheritDoc}
     */
    public byte[] toBytes() throws Exception {
        
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            bos.write(Bytes.toMetaBytes(command));
            bos.write(Bytes.toBytes(argdata.size()));
            
            for (String name : argdata.keySet()) {
                bos.write(Bytes.toMetaBytes(name));
                bos.write(Bytes.toMetaBytes(argdata.get(name)));
            }
        }
        catch (IOException e) {
            Exceptions.throwFakeException(e);
        }
        return bos.toByteArray();
    }
    
    /**
     * {@inheritDoc}
     */
    public ShellQueryBody ofBytes(byte[] bs, int offset, int length) throws Exception {
        ByteMeta<ShellQueryBody> bm = ofBytes(bs, offset);
        return (bm.byteSize() != length) ? null : bm.instance();
    }
    
    /**
     * {@inheritDoc}
     */
    public ByteMeta<ShellQueryBody> ofBytes(byte[] bytes, int offset) throws Exception {
        ShellQueryBody inst = null;
        int size = 0;
        ByteMeta<String> cmd = Bytes.ofMetaBytes(bytes, offset);
        if (cmd.byteSize() > 0) {
            inst = new ShellQueryBody(cmd.instance());
            size += cmd.byteSize();
            int count = Bytes.toInt(bytes, offset + size, Bytes.BYTES_INT);
            size += Bytes.BYTES_INT;
            for (int i = 0; i < count; i++) {
                ByteMeta<String> name = Bytes.ofMetaBytes(bytes, offset + size);
                ByteMeta<String> data = Bytes.ofMetaBytes(bytes, offset + size + name.byteSize());
                if (name.byteSize() > 0 && data.byteSize() > 0) {
                    inst.addArgument(name.instance(), data.instance());
                    size += name.byteSize() + data.byteSize();
                }
            }
        }
        
        return ByteMeta.of(inst, size);
    }
    
    /**
     * @return the command
     */
    public String getCommand() {
        return command;
    }
    
    /**
     * @return the argument
     */
    public Map<String, String> getArgument() {
        return argdata;
    }
    
    /**
     * add argument
     * 
     * @param name the name
     * @param data the data
     * @throws NullPointerException if name is null
     */
    public void addArgument(String name, String data) {
        argdata.put(name, data);
    }
}
